using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace CtxReader {
	internal enum CommandCodes {
		Text=48,
		CenteredText=49,
		ClearScreen=50,
		Caption=51,
		Field=52,
		SelectList=53,
		BarCode=54,
		HiddenField=55,
		Delay=56,
		ErrorIndicator=57,
		NonReverseCaption=58,
		InjectedMessage=59
	}

	public enum BarCodeTypes {
		Interleaved2of5=1,
		Code39=2,
		Code128=4
	}

	public enum BeepTypes {
		Error=1
	}
	/// <summary>
	/// class to build output frame which will be sent to RF device for interpretation
	/// </summary>
	[Serializable]
	public class OutputFrame {
		private string _sequence=null;
		private byte _resend=0;
		private ByteBuffer _buffer=new ByteBuffer(128);
		/////////////////////////////////////////////////////////////////////
		// constructor(s)
		private OutputFrame() {
		}
		public OutputFrame(string sequence) {
			_sequence=sequence;
		}
		public void Copy(OutputFrame copy) {
			_sequence=copy._sequence;
			_buffer.Copy(copy.Bytes);
		}
		public void SetResendFlag() {
			_resend=1;
		}
		/////////////////////////////////////////////////////////////////////
		// get the buffer length
		public int Length {
			get {
				return _buffer.Length;
			}
		}
		/////////////////////////////////////////////////////////////////////
		// get the seqence number
		public string Sequence {
			get {
				return _sequence;
			}
		}
		public ByteBuffer Bytes {
			get {
				return _buffer;
			}
		}
		/////////////////////////////////////////////////////////////////////
		// get the raw buffer for sending
		public byte[] Buffer {
			get {
				byte[] buffer=_buffer.GetBytes();
				byte[] result=new byte[_sequence.Length+_buffer.Length+1];
				System.Text.Encoding.ASCII.GetBytes(_sequence,0,_sequence.Length,result,0);
				result[_sequence.Length]=_resend;
				Array.Copy(buffer,0,result,_sequence.Length+1,buffer.Length);
				return result;
			}
		}
		public void Dump() {
			byte[] buffer=_buffer.GetBytes();
			byte[] result=new byte[_sequence.Length+_buffer.Length+1];
			System.Text.Encoding.ASCII.GetBytes(_sequence,0,_sequence.Length,result,0);
			result[_sequence.Length]=_resend;
			Array.Copy(buffer,0,result,_sequence.Length+1,buffer.Length);
			Console.WriteLine("\nOutputFrame ( {0} ):",(_resend==1)?"Resend":"Normal");
			for(int i=0;i<result.Length;i++)
			{
				Console.WriteLine("  output byte[{0:000}]={1:000} ({2})",i,result[i],(result[i]>=32)?(char)result[i]:'.');
			}
		}
		public string DiagnosticDumpToConsole() {
			StringBuilder sb=new StringBuilder();
			byte[] buffer=_buffer.GetBytes();
			byte[] result=new byte[_sequence.Length+_buffer.Length+1];
			System.Text.Encoding.ASCII.GetBytes(_sequence,0,_sequence.Length,result,0);
			result[_sequence.Length]=_resend;
			Array.Copy(buffer,0,result,_sequence.Length+1,buffer.Length);
			sb.AppendLine(string.Format("\nframe #{0} ( {1} )\n",this._sequence,(_resend==1)?"Resend":"Normal"));
			int i=_sequence.Length+1;
			while(i<result.Length)
			{
				CommandCodes command=(CommandCodes)result[i];
				switch(command)
				{
				case CommandCodes.ClearScreen:
				sb.AppendLine(string.Format("  CLS             : LINE(S) {0} TO {1}",result[i+1],result[i+2]));
				i+=2;
				break;
				case CommandCodes.Caption:
				sb.AppendLine(string.Format("  CAPTION         : {0}",Encoding.ASCII.GetString(result,i+2,result[i+1])));
				i+=result[i+1]+1;
				break;
				case CommandCodes.NonReverseCaption:
				sb.AppendLine(string.Format("  CAPTION (NREV)  : {0}",Encoding.ASCII.GetString(result,i+2,result[i+1])));
				i+=result[i+1]+1;
				break;
				case CommandCodes.Text:
				sb.AppendLine(string.Format("  TEXT    @ {0:00},{1:00} : {2}",result[i+1],result[i+2],
						Encoding.ASCII.GetString(result,i+5,result[i+4])));
				i+=result[i+4]+4;
				break;
				case CommandCodes.BarCode:
				sb.AppendLine(string.Format("  BARCODE @ {0:00},{1:00} : {2}-{3} CHARS ({4})",
						result[i+1],result[i+2],result[i+3],result[i+4],
						((BarCodeTypes)result[i+5]).ToString()));
				i+=6;
				break;
				default:
				sb.AppendLine(string.Format("  BYTE[{0:000}] = {1:000} ({2})",i,result[i],(result[i]>=32)?(char)result[i]:'.'));
				break;
				}
				i++;
			}
			Console.WriteLine(sb.ToString());
			return sb.ToString();
		}
		/////////////////////////////////////////////////////////////////////
		// add text
		public void AddText(int row,int col,string format,params object[] args) {
			string text=string.Format(format,args);
			_buffer.Append((byte)CommandCodes.Text);
			_buffer.Append((byte)row);
			_buffer.Append((byte)col);
			_buffer.Append(0x00);
			_buffer.Append((byte)text.Length);
			_buffer.Append(Encoding.ASCII.GetBytes(text));
		}
		/////////////////////////////////////////////////////////////////////
		// add centered text
		public void AddText(int row,string format,params object[] args) {
			string text=string.Format(format,args);
			_buffer.Append((byte)CommandCodes.Text);
			_buffer.Append((byte)row);
			int col=1;
			if(text.Length<26)
			{
				col=13-(text.Length/2);
			}
			_buffer.Append((byte)col);
			_buffer.Append(0x00);
			_buffer.Append((byte)text.Length);
			_buffer.Append(Encoding.ASCII.GetBytes(text));
		}
		/////////////////////////////////////////////////////////////////////
		// add reverse video text
		public void AddReverseText(int row,int col,string format,params object[] args) {
			string text=string.Format(format,args);
			_buffer.Append((byte)CommandCodes.Text);
			_buffer.Append((byte)row);
			_buffer.Append((byte)col);
			_buffer.Append(0x01);
			_buffer.Append((byte)text.Length);
			_buffer.Append(Encoding.ASCII.GetBytes(text));
		}
		/////////////////////////////////////////////////////////////////////
		// add clear screen command
		public void AddCls() {
			AddCls(2,20);
		}
		/////////////////////////////////////////////////////////////////////
		// add clear screen command with optional clear of top line
		public void AddCls(bool clearCaptionLine) {
			if(clearCaptionLine)
			{
				AddCls(1,20);
			}
			else
			{
				AddCls(2,20);
			}
		}
		/////////////////////////////////////////////////////////////////////
		// add error command
		public void AddErrorIndicator() {
			_buffer.Append((byte)CommandCodes.ErrorIndicator);
		}
		/////////////////////////////////////////////////////////////////////
		// add clear screen command
		public void AddCls(int minrow,int maxrow) {
			_buffer.Append((byte)CommandCodes.ClearScreen);
			_buffer.Append((byte)minrow);
			_buffer.Append((byte)maxrow);
		}
		/////////////////////////////////////////////////////////////////////
		// add caption
		public void AddCaption(string format,params object[] args) {
			string text=string.Format(format,args);
			_buffer.Append((byte)CommandCodes.Caption);
			_buffer.Append((byte)text.Length);
			_buffer.Append(Encoding.ASCII.GetBytes(text));
		}
		/////////////////////////////////////////////////////////////////////
		// add non reverse caption
		public void AddNonReverseCaption(string format,params object[] args) {
			string text=string.Format(format,args);
			_buffer.Append((byte)CommandCodes.NonReverseCaption);
			_buffer.Append((byte)text.Length);
			_buffer.Append(Encoding.ASCII.GetBytes(text));
		}
		/////////////////////////////////////////////////////////////////////
		// add a prompted field
		public void AddField(int row,int col,string prompt,int minLength,int maxLength,bool alpha,bool numeric) {
			AddText(row,col,prompt);
			AddField(row,col+prompt.Length,minLength,maxLength,alpha,numeric);
		}
		/////////////////////////////////////////////////////////////////////
		// add a field
		public void AddField(int row,int col,int minLength,int maxLength,bool alpha,bool numeric) {
			byte flags=0;
			flags|=(alpha)?(byte)1:(byte)0;
			flags|=(numeric)?(byte)2:(byte)0;
			_buffer.Append((byte)CommandCodes.Field);
			_buffer.Append((byte)row);
			_buffer.Append((byte)col);
			_buffer.Append(flags);
			_buffer.Append((byte)minLength);
			_buffer.Append((byte)maxLength);
		}
		/////////////////////////////////////////////////////////////////////
		// add a select list
		public void AddSelectList(int row,int col,int height,int width,string[] options) {
			_buffer.Append((byte)CommandCodes.SelectList);
			_buffer.Append((byte)row);
			_buffer.Append((byte)col);
			_buffer.Append((byte)height);
			_buffer.Append((byte)width);
			_buffer.Append((byte)options.Length);
			for(int i=0;i<options.Length;i++)
			{
				_buffer.Append((byte)options[i].Length);
				_buffer.Append(Encoding.ASCII.GetBytes(options[i]));
			}
		}
		/////////////////////////////////////////////////////////////////////
		// add a barcode with prompt
		public void AddBarCode(int row,int col,string prompt,int minlen,int maxlen,BarCodeTypes codeType) {
			AddText(row,col,prompt);
			AddBarCode(row,col+prompt.Length,minlen,maxlen,codeType);
		}
		/////////////////////////////////////////////////////////////////////
		// add a barcode
		public void AddBarCode(int row,int col,int minlen,int maxlen,BarCodeTypes codeType) {
			_buffer.Append((byte)CommandCodes.BarCode);
			_buffer.Append((byte)row);
			_buffer.Append((byte)col);
			_buffer.Append((byte)minlen);
			_buffer.Append((byte)maxlen);
			_buffer.Append((byte)codeType);
		}
		/////////////////////////////////////////////////////////////////////
		// add a hidden field
		public void AddHiddenField(string name,string fieldValue) {
			_buffer.Append((byte)CommandCodes.HiddenField);
			_buffer.Append((byte)name.Length);
			_buffer.Append(Encoding.ASCII.GetBytes(name));
			_buffer.Append((byte)fieldValue.Length);
			_buffer.Append(Encoding.ASCII.GetBytes(fieldValue));
		}
		/////////////////////////////////////////////////////////////////////
		// add a delay (will disable automatic wait for keypress)
		public void AddDelay(int delay) {
			_buffer.Append((byte)CommandCodes.Delay);
			_buffer.Append((byte)delay);
		}
		/////////////////////////////////////////////////////////////////////
		// add a delay (will disable automatic wait for keypress)
		public void AddInjectedMessage(string text) {
			_buffer.Append((byte)CommandCodes.InjectedMessage);
			_buffer.Append((byte)text.Length);
			_buffer.Append(Encoding.ASCII.GetBytes(text));
		}
	}
}
